package com.lancoo.answer.widget

import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.os.Handler
import android.os.Parcelable
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import com.lancoo.answer.R
import com.lancoo.answer.util.DensityUtils
import java.util.*

class VoiceWaveView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : View(context, attrs, defStyle) {

    var bodyWaveList = LinkedList<Int>()
        private set
    var headerWaveList = LinkedList<Int>()
        private set
    var footerWaveList = LinkedList<Int>()
        private set

    private var waveList = LinkedList<Int>()

    var scaleArry = arrayOf(1f,1f,1f,1f,1f)
    var delay=  arrayOf(490,300,240,560,700)

    /**
     * 线间距 px
     */
    var lineSpace: Float = 10f
    /**
     * 线宽 px
     */
    var lineWidth: Float = 20f

    /**
     * 动画持续时间
     */
    var duration: Long = 500
    /**
     * 线颜色
     */
    var lineColor: Int = Color.BLUE
    var paintLine: Paint? = null
    var paintPathLine: Paint? = null

//    private var valueAnimator = ValueAnimator.ofFloat(1.0f,0.5f, 1f)
    private var valueAnimators = mutableListOf<ValueAnimator>()
    private var valueAnimatorOffset: Float = 1f

    private var valHandler = Handler()
    val linePath = Path()

    private var isPlaying = false

    @Volatile
    var isStart: Boolean = false
        private set

    /**
     * 跳动模式
     */
    var waveMode: WaveMode = WaveMode.UP_DOWN

    /**
     * 线条样式
     */
    var lineType: LineType = LineType.BAR_CHART

    /**
     * 显示位置
     */
    var showGravity: Int = Gravity.LEFT or Gravity.BOTTOM

    private var runnable: Runnable? = null


    init {
        attrs?.let {
            val typedArray = context.theme.obtainStyledAttributes(
                attrs,
                R.styleable.VoiceWaveView, 0, 0
            )

            lineWidth = typedArray.getDimension(R.styleable.VoiceWaveView_lineWidth, 20f)
            lineSpace = typedArray.getDimension(R.styleable.VoiceWaveView_lineSpace, 10f)
            duration = typedArray.getInt(R.styleable.VoiceWaveView_duration, 700).toLong()
            showGravity = typedArray.getInt(R.styleable.VoiceWaveView_android_gravity, Gravity.LEFT or Gravity.BOTTOM)
            lineColor = typedArray.getInt(R.styleable.VoiceWaveView_lineColor, Color.BLUE)
            val mode = typedArray.getInt(R.styleable.VoiceWaveView_waveMode, 0)
            when (mode) {
                0 -> waveMode = WaveMode.UP_DOWN
                1 -> waveMode = WaveMode.LEFT_RIGHT
            }

            val lType = typedArray.getInt(R.styleable.VoiceWaveView_lineType, 0)
            when (lType) {
                0 -> lineType = LineType.BAR_CHART
                1 -> lineType = LineType.LINE_GRAPH
            }

            typedArray.recycle()
        }

        paintLine = Paint()
        paintLine?.isAntiAlias = true
        paintLine?.strokeCap = Paint.Cap.ROUND

        paintPathLine = Paint()
        paintPathLine?.isAntiAlias = true
        paintPathLine?.setStyle(Paint.Style.STROKE);

        initwave()
    }

    /**
     * 线的高度 0,100 百分数
     */
    fun addBody(num: Int) {
        checkNum(num)
        bodyWaveList.add(num)
    }

    /**
     * 头部线的高度 0,100 百分数
     */
    fun addHeader(num: Int) {
        checkNum(num)
        headerWaveList.add(num)
    }

    /**
     * 尾部线的高度 0,100 百分数
     */
    fun addFooter(num: Int) {
        checkNum(num)
        footerWaveList.add(num)
    }

    private fun checkNum(num: Int) {
        if (num < 0 || num > 100) {
            throw Exception("num must between 0 and 100")
        }
    }

    /**
     * 开始
     */
    fun start() {
        if (isStart) {
            return
        }
        randomWave()
        isStart = true
        if (waveMode == WaveMode.UP_DOWN) {
            for (index in 0 until 5){
                var valueAnimator  = ValueAnimator.ofFloat(1.0f,0.3f,0.6f,1.3f)
                if (index%2 == 0){
                    valueAnimator = ValueAnimator.ofFloat(1.0f,0.3f,0.6f,1.3f)
                }else{
                    valueAnimator = ValueAnimator.ofFloat(1.0f,1.3f,0.6f,1.0f)
                }
                valueAnimator.duration = duration
                valueAnimator.repeatMode = ValueAnimator.REVERSE
                valueAnimator.repeatCount = ValueAnimator.INFINITE
                valueAnimator.startDelay = delay[index].toLong()
                valueAnimator.addUpdateListener {
                    valueAnimatorOffset = it.getAnimatedValue() as Float
                    scaleArry[index] = valueAnimatorOffset;

                    //循环改变每个指针高度
                    invalidate()
                }
                valueAnimator.start()
                valueAnimators.add(valueAnimator)
            }
        } else if (waveMode == WaveMode.LEFT_RIGHT) {
            runnable = object : Runnable {
                override fun run() {
                    val last = bodyWaveList.pollLast()
                    bodyWaveList.addFirst(last)
                    invalidate()
                    valHandler.postDelayed(this,duration);
                }
            }
            valHandler.post(runnable as Runnable)
        } else {

        }
    }

    fun initwave(){
        waveList.clear()
        bodyWaveList.clear()

        for (index in 0 until if (DensityUtils.isPad(context))14*15 else 7*15){
            addBody(5)
        }
    }

    fun randomWave(){
        waveList.clear()
        bodyWaveList.clear()
//            waveView.addBody(27);
//            waveView.addBody(17);
//            waveView.addBody(38);
//            waveView.addBody(55);
//            waveView.addBody(61);
//            waveView.addBody(61);
//            waveView.addBody(55);
//            waveView.addBody(38);
//            waveView.addBody(24);
        for (index in 0 until if (DensityUtils.isPad(context))14 else 7){
            addBody(8 + 5)
            addBody(20 + 5)
            addBody(38 + 5)
            addBody(14 + 5)
            addBody(8 + 5)

            addBody(17)
            addBody(27)
            addBody(38)
            addBody(55)
            addBody(71)
            addBody(55)
            addBody(38)
            addBody(24)

            addBody(8 + 5)
            addBody(20 + 5)
            addBody(38 + 5)
            addBody(14 + 5)
            addBody(8 + 5)
        }

    }
    val mRandom = Random()

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        waveList.clear()
        waveList.addAll(headerWaveList)
        waveList.addAll(bodyWaveList)
        waveList.addAll(footerWaveList)

        linePath.reset()
        paintPathLine?.strokeWidth = lineWidth
        paintPathLine?.color = lineColor

        paintLine?.strokeWidth = lineWidth
        paintLine?.color = lineColor
        for (i in waveList.indices) {
            var startX = 0f
            var startY = 0f
            var endX = 0f
            var endY = 0f

            var offset = 1f
            if (i >= headerWaveList.size && i < (waveList.size - footerWaveList.size)) {//模式1 ，排除掉头尾
                if (isStart){
//                    offset = mRandom.nextFloat();
                    offset = scaleArry[(i)%5];
                }else{
                    offset = 1f;
                }
//                offset = valueAnimatorOffset;
            }

//            if (i < headerWaveList.size || i >= (waveList.size - footerWaveList.size)){
//                paintLine?.color = Color.parseColor("#8EE5EE");
//            }else{
//                if (i >= headerWaveList.size && i<waveList.size-footerWaveList.size-20){
//                    paintLine?.color = Color.parseColor("#4876FF");
//                }else{
//                    paintLine?.color = lineColor
//                }
//
//            }


            val lineHeight = waveList[i]/ 100.0 * measuredHeight  * offset

            val absoluteGravity = Gravity.getAbsoluteGravity(showGravity, layoutDirection);

            when (absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK) {
                Gravity.CENTER_HORIZONTAL -> {
                    val lineSize = waveList.size
                    val allLineWidth = lineSize * (lineSpace + lineWidth)
                    if (allLineWidth < measuredWidth) {
                        startX = (i * (lineSpace + lineWidth) + lineWidth / 2) + ((measuredWidth - allLineWidth) / 2)
                    } else {
                        startX = i * (lineSpace + lineWidth) + lineWidth / 2
                    }
                    endX = startX
                }

                Gravity.RIGHT -> {
                    val lineSize = waveList.size
                    val allLineWidth = lineSize * (lineSpace + lineWidth)
                    if (allLineWidth < measuredWidth) {
                        startX = (i * (lineSpace + lineWidth) + lineWidth / 2) + (measuredWidth - allLineWidth)
                    } else {
                        startX = i * (lineSpace + lineWidth) + lineWidth / 2
                    }
                    endX = startX
                }

                Gravity.LEFT -> {
                    startX = i * (lineSpace + lineWidth) + lineWidth / 2
                    endX = startX
                }
            }


            when (showGravity and Gravity.VERTICAL_GRAVITY_MASK) {
                Gravity.TOP -> {
                    startY = 0f
                    endY = lineHeight.toFloat()
                }

                Gravity.CENTER_VERTICAL -> {
                    startY = (measuredHeight / 2 - lineHeight / 2).toFloat()
                    endY = (measuredHeight / 2 + lineHeight / 2).toFloat()
                }

                Gravity.BOTTOM -> {
                    startY = (measuredHeight - lineHeight).toFloat()
                    endY = measuredHeight.toFloat()
                }

            }
            if (lineType == LineType.BAR_CHART) {
                canvas?.drawLine(
                    startX,
                    startY,
                    endX,
                    endY,
                    paintLine!!
                )
            }
            if (lineType == LineType.LINE_GRAPH) {
                if (i == 0) {
                    linePath.moveTo(startX, startY)
                    val pathEndX = endX + (lineWidth / 2) + (lineSpace / 2)
                    linePath.lineTo(pathEndX, endY)
                } else {
                    linePath.lineTo(startX, startY)
                    val pathEndX = endX + (lineWidth / 2) + (lineSpace / 2)
                    linePath.lineTo(pathEndX, endY)
                }
            }
        }
        if (lineType == LineType.LINE_GRAPH) {
            canvas?.drawPath(linePath, paintPathLine!!)
        }
    }

    /**
     * 停止 onDestroy call
     */
    fun stop() {
        isStart = false
        initwave()
        invalidate()
        if (runnable != null) {
            valHandler.removeCallbacks(runnable!!)
        }
        for (value in valueAnimators){
            value.cancel()
        }
//        valueAnimator.cancel()
    }

    override fun onSaveInstanceState(): Parcelable? {
        //TODO onSaveInstanceState
        return super.onSaveInstanceState()
    }

    override fun onRestoreInstanceState(state: Parcelable?) {
        //TODO onRestoreInstanceState
        super.onRestoreInstanceState(state)
    }
}